Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 25, 2026

Adds Ledger hardware wallet integration using @hot-labs/near-connect's custom wallet executor framework, bringing feature parity with the Web4 implementation.

Video generated from Playwright test

ledgerlogin.mp4

Implementation

Executor (public/ledger-executor.js)

  • Self-contained script with CDN imports (esm.sh) for Ledger/NEAR dependencies
  • LedgerClient class handles APDU communication (CLA 0x80, 250-byte chunking, derivation path 44'/397'/0'/0'/1')
  • Full wallet interface: signIn, signOut, getAccounts, signAndSendTransaction(s), signMessage (NEP-413)
  • Account ID input UI since Ledger only provides public key
  • Verifies public key has FullAccess via RPC before sign-in

Manifest (lib/ledger-manifest.ts)

{
  id: "ledger",
  executor: "/ledger-executor.js",
  type: "sandbox",
  permissions: { storage: true, usb: true, hid: true }
}

Registration (stores/near-store.ts)

  • Registers Ledger wallet after connector initialization
  • Conditional on WebHID API availability (Chrome/Edge/Opera desktop only)

E2E Testing

Playwright Test (e2e/ledger-login.spec.ts)

  • Full WebHID API mock that simulates Ledger device responses
  • Mocks GET_PUBLIC_KEY to return the sandbox's test.near public key
  • RPC interception redirects FastNEAR calls to local sandbox
  • 500ms mock response delay matches real device timing (prevents iframe race condition)
  • Video recording enabled for test documentation

Browser Support

WebHID API requirement limits support to Chrome/Edge/Opera 89+ on desktop. Gracefully skips registration on unsupported browsers (Firefox, Safari, mobile).

Dependencies

All dependencies loaded from CDN (no build-time imports):

Documentation

  • docs/ledger-wallet-support.md: Technical architecture, APDU protocol details, security model
  • docs/ledger-testing-guide.md: Manual testing procedures for device interaction

Resolves #89

Copilot AI changed the title [WIP] Add Ledger hardware wallet support to treasury26 app feat: add Ledger hardware wallet support Jan 25, 2026
Copilot AI requested a review from petersalomonsen January 25, 2026 19:47
Copilot stopped work on behalf of petersalomonsen due to an error January 29, 2026 18:56
petersalomonsen and others added 14 commits January 29, 2026 19:00
- Add user gesture prompt for WebHID connection in sandbox iframe
- Fix RPC endpoint to use FastNEAR instead of broken window.selector.providers
- Update @near-js/transactions imports to use actionCreators namespace
- Add connectWithDevice method for pre-authorized devices
- Add Playwright configuration and Ledger login test
- Add GitHub Actions workflow for E2E tests
- Add Docker Compose setup for running tests with sandbox
- Update devcontainer with desktop-lite for Playwright UI
- Add test artifacts to .gitignore
- Add comprehensive WebHID API mock that intercepts navigator.hid
- Implement MockHIDDevice class with proper Ledger HID framing
- Handle APDU commands: GET_PUBLIC_KEY, SIGN_TRANSACTION, GET_VERSION
- Echo back channel ID from requests (fixes "Invalid channel" error)
- Use sandbox genesis public key (ed25519:5BGSaf6YjVm7565VzWQHNxoyEjwr3jUpRJSGjREvU9dB)
- Use context.addInitScript() to inject mock before any JS runs

The mock successfully:
- Shows the "Connect Ledger" button
- Handles requestDevice() calls
- Returns mock public key from Ledger
- Shows account ID input dialog

Note: Full E2E flow requires sandbox to be running for access key verification.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Wait for account ID input to be attached (not visible) since iframe hides quickly
- Use frame.evaluate() to fill and click confirm in single JS execution
- Add stabilization wait before clicking Connect Ledger button
- Add comprehensive console logging for debugging

The test now passes with the WebHID mock:
- Connect Ledger button appears and is clickable
- Mock handles requestDevice() and GET_PUBLIC_KEY
- Account ID is filled and confirm is clicked

Note: RPC verification still calls mainnet instead of sandbox,
causing a "FullAccess permission" error that doesn't fail the test.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Redirect FastNEAR RPC calls to local sandbox for access key verification
and add assertion to verify successful login redirect.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add pauses between steps for clearer video recording
- Force iframe visibility to show account ID input
- Type account ID character by character for visual effect
- Add final pause to show successful login result

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Increase iframe height to 320px to show all content
- Make iframe parent elements visible with proper z-index
- Style input field with white background and large font for video visibility
- Type characters with 200ms delay for clear video capture
- Add visual button feedback before clicking confirm

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Remove heavy CSS overrides that replaced the Ledger library's dialog.
Now only make the iframe parent chain visible (minimal fix for Playwright)
while preserving the original dark-themed "Enter Account ID" dialog.

The typing is clearly visible in the original Ledger dialog.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
The mock's 10ms response delay caused a race condition with the wallet
selector's iframe hide/show transitions, causing the account ID dialog
to fade out immediately. Increased to 500ms to match real Ledger timing.

Changes:
- Increase mock response delay from 10ms to 500ms
- Fix RPC route pattern to properly intercept FastNEAR URLs
- Remove CSS visibility hack (no longer needed)
- Add 120s test timeout for video recording pauses
- Enable video recording in playwright config

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Change platform from {} to [] to match WalletManifest type
- Add test video artifact upload to E2E workflow

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add signTransaction: true to ledger manifest features
- Remove npm cache from setup-node (was causing path resolution errors)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Project uses bun.lock (package-lock.json is gitignored), so the E2E
workflow needs to use bun for dependency installation.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@petersalomonsen
Copy link
Collaborator

@race-of-sloths include

@race-of-sloths
Copy link

race-of-sloths commented Jan 31, 2026

@Copilot Thank you for your contribution! Your pull request is now a part of the Race of Sloths!
Weekly streak is on the road, smart strategy! Secure your streak with another PR!

Shows inviting banner with latest news.

Shows profile picture for the author of the PR

Current status: waiting for finalization

The pull request is merged, you have 24 hours to finalize your scoring. The scoring ends Wed Feb 4 16:41:29 2026

Reviewer Score
@petersalomonsen 5

Your contribution is much appreciated with a final score of 5!
You have received 50 Sloth points for this contribution

@petersalomonsen received 25 Sloth Points for reviewing and scoring this pull request.

What is the Race of Sloths

Race of Sloths is a friendly competition where you can participate in challenges and compete with other open-source contributors within your normal workflow

For contributors:

  • Tag @race-of-sloths inside your pull requests
  • Wait for the maintainer to review and score your pull request
  • Check out your position in the Leaderboard
  • Keep weekly and monthly streaks to reach higher positions
  • Boast your contributions with a dynamic picture of your Profile

For maintainers:

  • Score pull requests that participate in the Race of Sloths and receive a reward
  • Engage contributors with fair scoring and fast responses so they keep their streaks
  • Promote the Race to the point where the Race starts promoting you
  • Grow the community of your contributors

Feel free to check our website for additional details!

Bot commands
  • For contributors
    • Include a PR: @race-of-sloths include to enter the Race with your PR
  • For maintainers:
    • Invite contributor @race-of-sloths invite to invite the contributor to participate in a race or include it, if it's already a runner.
    • Assign points: @race-of-sloths score [1/2/3/5/8/13] to award points based on your assessment.
    • Reject this PR: @race-of-sloths exclude to send this PR back to the drawing board.
    • Exclude repo: @race-of-sloths pause to stop bot activity in this repo until @race-of-sloths unpause command is called

@petersalomonsen petersalomonsen marked this pull request as ready for review January 31, 2026 08:39
@petersalomonsen
Copy link
Collaborator

@race-of-sloths score 5

- Fix base64 encoding for broadcast_tx_commit RPC call
- Remove double JSON serialization of function call args

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@@ -0,0 +1,666 @@
// Ledger Hardware Wallet Executor for hot-connect
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we move this to hot connect instead and use newer version?

Resolve conflicts in near-store.ts by keeping both Ledger wallet
support and new auth API imports.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@petersalomonsen petersalomonsen merged commit 2c22d11 into main Feb 3, 2026
6 checks passed
@petersalomonsen petersalomonsen deleted the copilot/add-ledger-support-treasury26 branch February 3, 2026 16:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Ledger for wallet sign in

4 participants